Shell Script
contents
쉘 스크립트 문법은 시스템 명령어, 제어 구조, 변수들을 조합하여 자동화된 프로그램을 만들기 위한 규칙의 집합입니다. Java나 Python 같은 언어와 달리, 쉘 스크립트는 기본적으로 쉘(예: bash)이 순차적으로 실행하는 명령어들의 목록입니다.
"문법"은 사실상 그 실행 흐름을 어떻게 제어하느냐에 관한 것입니다. 가장 일반적이고 강력한 쉘인 bash를 중심으로 아주 자세히 설명해 드리겠습니다.
1. 쉬뱅 (The Shebang, #!)
스크립트는 항상 운영체제에게 이 파일을 실행할 때 어떤 쉘을 사용할지 알려주는 "쉬뱅"으로 시작해야 합니다.
#!/bin/bash
# 이것은 주석입니다
#!: "쉬뱅" 또는 "해시뱅"이라고 부릅니다./bin/bash:bash인터프리터의 경로입니다. 사용자의 기본 쉘이 다르더라도(zsh나 fish 등), 이 스크립트는 무조건bash로 실행되도록 보장합니다.
2. 변수와 파라미터
변수 선언
= 기호를 사용하여 값을 할당합니다. = 양옆에 공백이 있으면 안 됩니다.
# 좋음
my_var="Hello World"
# 나쁨 (my_var라는 명령어를 실행하려고 시도함)
my_var = "Hello World"
변수 사용
$ 기호를 사용하여 변수 값에 접근합니다. 모호함을 피하기 위해 변수 이름을 중괄호로 감싸는 것이 가장 좋은 습관입니다.
my_var="Hello"
echo $my_var # 출력: Hello
echo "${my_var} World" # 출력: Hello World
위치 파라미터 (인자, Arguments)
스크립트가 실행될 때 쉘에 의해 자동으로 설정되는 변수들입니다.
$0: 스크립트 자체의 이름.$1: 첫 번째 인자.$2: 두 번째 인자 (계속 이어짐).$@: 모든 인자들의 배열. 모든 입력을 반복(iterate)할 때 가장 많이 사용됩니다.$#: 인자의 개수.
3. 따옴표와 치환 (매우 중요!)
쉘 문법에서 가장 중요하며, 대부분의 버그가 발생하는 원인입니다.
작은따옴표 ('...')
- "강한" 또는 "문자 그대로(Literal)"의 인용.
- 안에 있는 모든 것을 문자 그대로 취급합니다.
$나*같은 특수 문자가 의미를 잃습니다.
echo 'Your variable is $my_var'
# 출력: Your variable is $my_var
큰따옴표 ("...")
- "약한" 또는 "확장(Expanding)" 인용.
- 일반적으로 원하는 방식입니다. 쉘이 변수(
$my_var)와 명령어 치환($(...))을 확장(해석)하도록 허용합니다. - 모범 사례: 공백으로 인한 문제를 방지하기 위해 변수는 항상 큰따옴표로 감싸세요.
my_var="Hello World"
echo "The message is: $my_var"
# 출력: The message is: Hello World
명령어 치환 $(...)
명령어를 실행하고 그 출력 을 해당 위치에 "붙여넣기" 합니다.
# 'ls'의 출력을 변수에 캡처
file_list=$(ls)
# 출력을 직접 사용
echo "You are in directory: $(pwd)"
- 레거시: 오래된 스크립트에서는 백틱(
`pwd`)을 볼 수 있습니다. 읽기 어렵고 중첩해서 사용할 수 없으므로 사용하지 마세요.$(...)가 현대적인 표준입니다.
4. I/O: 파이프와 리디렉션
|(파이프): 왼쪽 명령여의stdout을 가져와 오른쪽 명령어의stdin으로 "연결"합니다.
# 'error' 라인을 모두 찾은 다음, 그 줄 수를 셈
grep "ERROR" my_log.log | wc -l
>(stdout 리디렉션): 출력을 파일에 덮어씁니다.
echo "Hello" > new_file.txt
>>(stdout 리디렉션): 출력을 파일 끝에 추가(append)합니다.
echo "Another line" >> new_file.txt
2>(stderr 리디렉션): 에러 메시지만 리디렉션합니다.
# 명령어를 실행하되, 에러는 error.log로 보냄
./my_script.sh 2> error.log
&>(stdout & stderr 리디렉션): 모든 출력을 하나의 파일로 리디렉션합니다.
./my_script.sh &> all_output.log
5. 조건문: if, [, 그리고 [[
쉘 문법에서 가장 헷갈리는 부분입니다. if 문은 불리언(참/거짓)을 확인하는 게 아닙니다. 명령어의 종료 코드(exit code) 를 확인합니다.
- 종료 코드
0: 성공 (또는 "true"). - 종료 코드
1(또는 0이 아닌 값): 실패 (또는 "false").
if 문
구조는 if [명령어]; then ... fi 입니다.
# 'grep'은 텍스트를 찾으면 0(성공), 못 찾으면 1(실패)을 반환합니다.
if grep "ERROR" my_log.log; then
echo "An error was found!"
fi
test 와 [
프로그램 실행이 아니라 변수를 비교하고 싶다면? test 명령어를 사용합니다. [는 test 명령어의 짧은 이름일 뿐입니다.
파일 확인:
-f "$FILE": 파일이면 참.-d "$DIR": 디렉터리면 참.-e "$PATH": 존재하면 참.
문자열 확인:
"$VAR1" == "$VAR2": 문자열이 같으면 참.-z "$VAR": 문자열이 비어 있으면(길이가 0) 참.
숫자 확인 (>나 <를 쓰지 마세요!):
$NUM1 -eq $NUM2: 같음 (Equal)$NUM1 -ne $NUM2: 같지 않음 (Not equal)$NUM1 -gt $NUM2: 큼 (Greater than)$NUM1 -lt $NUM2: 작음 (Less than)$NUM1 -ge $NUM2: 크거나 같음$NUM1 -le $NUM2: 작거나 같음
치명적 중요 사항: [ 안에서 변수를 사용할 때는 반드시 큰따옴표("$VAR")로 감싸야 합니다. 그렇지 않으면 변수가 비어 있거나 공백이 포함될 때 스크립트가 깨집니다.
# 'if'와 '[' 사용 예시
file_count=$(ls | wc -l)
if [ "$file_count" -gt 10 ]; then
echo "You have too many files!"
else
echo "You have a few files."
fi
[[ ... ]] (현대적인 bash 방식)
이것은 명령어가 아니라 bash 키워드이며, [의 현대적인 대체제입니다. 훨씬 안전하고 강력합니다.
- 변수를 따옴표로 감싸지 않아도 됩니다 (
[[ $file_count -gt 10 ]]). &&와||를 사용하여 로직을 결합할 수 있습니다.- 패턴 매칭을 지원합니다 (
[[ $filename == *.txt ]]).
경험 법칙: bash 스크립트를 작성한다면, [ 대신 [[ ... ]]를 사용하세요.
6. 반복문: for 와 while
for 루프
아이템 목록을 순회합니다.
# 문자열 목록 순회
for fruit in apple banana cherry; do
echo "I like $fruit"
done
# 명령어 출력 결과 순회
for file in $(ls); do
echo "Found file: $file"
done
while 루프
조건(명령어가 0을 반환하는 한)이 참일 동안 계속 실행합니다.
# 파일을 한 줄씩 읽기
while read -r line; do
echo "Line content: $line"
done < "my_file.txt"
7. 함수 (Functions)
함수를 사용해 명령어를 그룹화할 수 있습니다.
- 파라미터는 스크립트 인자처럼 전달됩니다 (
$1,$2,$@). - 값을 "반환"하려면,
echo(또는printf)를 사용하고 호출하는 쪽에서 명령어 치환으로 캡처해야 합니다. return키워드는 오직 종료 코드(0-255)를 설정하는 용도로만 쓰입니다.
# 1. 함수 정의
greet() {
local name="$1" # 'local'은 변수를 함수 내부 전용으로 만듭니다
if [ -z "$name" ]; then
echo "Error: No name provided." >&2 # 에러를 stderr로 보냄
return 1 # 실패 종료 코드 반환
fi
# stdout으로 출력하여 값을 "반환"
echo "Hello, $name"
}
# 2. 함수 호출 및 출력 캡처
greeting=$(greet "Jerry")
# 3. 함수의 종료 코드 확인 ($?)
if [ $? -eq 0 ]; then
echo "Success: $greeting"
else
echo "Function failed"
fi
기억해야 할 특수 변수들
$?: 마지막 명령어 의 종료 코드 (0은 성공, 0이 아니면 실패).$$: 현재 스크립트의 프로세스 ID (PID).$@: 모든 위치 파라미터를 각각의 문자열로 취급.$*: 모든 위치 파라미터를 하나의 문자열로 취급.
references